import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { CreateGoodDto } from './dto/create-good.dto';
import { UpdateGoodDto } from './dto/update-good.dto';
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { EntityManager, Repository } from 'typeorm';
import { Good } from './entities/good.entity';
import { Spec } from '../spec/entities/spec.entity';
import { Sku } from '../sku/entities/sku.entity';
import { GoodType } from '../good-type/entities/good-type.entity';
import { FindGoodDto } from './dto/find-good.dto';
import { skip } from 'rxjs';
import { ConfigService } from '@nestjs/config';
import { DeleteIds, imgDto } from '../dto/all-dto';
import Decimal from 'decimal.js';
import { raw } from 'express';

@Injectable()
export class GoodService {
  constructor(
    @InjectRepository(Good)
    private goodRepository: Repository<Good>,
    @ InjectRepository(GoodType)
    private goodTypeRepository: Repository<GoodType>,
    @InjectEntityManager()
    private entityManger: EntityManager,
    private configService: ConfigService,
    @InjectRepository(Spec)
    private specRepository: Repository<Spec>,
    @InjectRepository(Sku)
    private skuRepository: Repository<Sku>,
  ) {
  }

  async create(createGoodDto: CreateGoodDto) {
    const { name, description, img, goodType, specType, status, specIds, sku, price, stock } = createGoodDto;
    if (
      await this.goodRepository.createQueryBuilder().where('name = :name', { name }).getOne()
    ) throw new HttpException(`此商品[${name}]已创建`, HttpStatus.INTERNAL_SERVER_ERROR);

    if (specType === 1) {
      await this.entityManger.transaction(async transactionalEntityManager => {
        const { identifiers } = await transactionalEntityManager.createQueryBuilder(Good, 'good')
          .insert()
          .values({
            name,
            description,
            status,
            specType,
            img,
            goodType: await transactionalEntityManager.createQueryBuilder(GoodType, 'goodType').where('id = :id', { id: goodType }).getOne(),
          })
          .execute();
        //生成默认sku
        const { identifiers: skuIdentifiers } = await transactionalEntityManager.createQueryBuilder(Sku, 'sku')
          .insert()
          .values({
            specCombination: { '默认': name },
            stock,
            price,
            good: identifiers[0].id,
            img,
          }).execute();
        //sku 关联商品表
        await transactionalEntityManager.createQueryBuilder(Good, 'good')
          .update()
          .where('id = :id', { id: identifiers[0].id })
          .set({
            sku: skuIdentifiers[0].id,
          });
      });
    } else if (specType === 2) {
      const { raw } = await this.entityManger.transaction(async transactionalEntityManager => {
        return await transactionalEntityManager.createQueryBuilder(Good, 'good')
          .insert()
          .values({
            name,
            description,
            img,
            status,
            specType,
            goodType: await transactionalEntityManager.createQueryBuilder(GoodType, 'goodType').where('id = :id', { id: goodType }).getOne(),
          })
          .execute();
      });
      return raw.insertId;

    }
  }

  async findAll(findGoodDto: FindGoodDto) {
    const { page, pageSize, name, status, specType } = findGoodDto;

    const GoodBuilder = this.goodRepository.createQueryBuilder('good');

    if (name) {
      GoodBuilder.andWhere('name LIKE :name', { name: `%${name}%` });
    }

    if (status) {
      GoodBuilder.andWhere('status = :status', { status });
    }

    if (specType) {
      GoodBuilder.andWhere('specType = :specType', { specType });
    }

    const [list, total] = await GoodBuilder
      // .leftJoinAndSelect("good.sku", 'sku')
      // .leftJoinAndSelect("good.spec", 'spec')
      .skip((page - 1) * pageSize)
      .take(pageSize)
      .getManyAndCount();

    return {
      list,
      total,
    };
  }

  async findOne(id: number) {
    const GOOD = await this.goodRepository.createQueryBuilder().where('id = :id', { id }).getOne();
    if (GOOD.specType === 1) { //单规格
      const ONE = await this.goodRepository.createQueryBuilder('good')
        .where('good.id = :id', { id })
        .leftJoinAndSelect('good.goodType', 'goodType')
        .leftJoinAndSelect('good.spec', 'spec')
        .leftJoinAndSelect('good.sku', 'sku')
        .select([
          'good.name as name',
          'good.description as description',
          'good.img as img',
          'good.goodType as goodType',
          'good.img as img',
          'good.status as status',
          'good.specType as specType',
          'sku.price as price',
          'sku.stock as stock',
        ])
        .getRawOne();
      return {
        ...ONE,
        price: new Decimal(ONE.price).toNumber(),
      };
    } else if (GOOD.specType === 2) {//多规格
      const ONE = await this.goodRepository.createQueryBuilder('good')
        .where('good.id = :id', { id })
        .leftJoinAndSelect('good.goodType', 'goodType')
        .leftJoinAndSelect('good.spec', 'spec')
        .leftJoinAndSelect('spec.specValue', 'specValue')
        .leftJoinAndSelect('good.sku', 'sku')
        .getOne();

      return {
        ...ONE,
        goodType: ONE?.goodType?.id || null,
      };
    }
  }

  async update(updateGoodDto: UpdateGoodDto) {
    const { id, name, description, img, goodType, specType, status, specIds, sku, price, stock } = updateGoodDto;
    if (await this.goodRepository.createQueryBuilder().where('name = :name', { name }).andWhere('id != :id', { id }).getOne()) {
      throw new HttpException(`此商品[${name}]名已存在`, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    if (specType === 1) {//单规格
      const { raw } = await this.entityManger.transaction(async transactionalEntityManager => {
        await transactionalEntityManager.createQueryBuilder(Sku, 'sku')
          .update()
          .where('sku.goodId = :id', { id })
          .set({
            stock,
            price,
          })
          .execute();

        return await transactionalEntityManager.createQueryBuilder(Good, 'good')
          .update()
          .set({
            name,
            description,
            img,
            goodType: await transactionalEntityManager.createQueryBuilder(GoodType, 'goodType').where('id=:id', { id: goodType }).getOne(),
            specType,
            status,
          })
          .where('id=:id', { id })
          .execute();
      });
      return raw.insertId;
    } else if (specType === 2) {
      await this.entityManger.transaction(async transactionalEntityManager => {
        await transactionalEntityManager.createQueryBuilder(Good, 'good')
          .update()
          .set({
            name,
            description,
            img,
            goodType: await transactionalEntityManager.createQueryBuilder(GoodType, 'goodType').where('id=:id', { id: goodType }).getOne(),
            specType,
            status,
          })
          .where('id=:id', { id })
          .execute();

        await Promise.all(sku.map(async (item) => {
          const { specCombination, price, stock, id: skuId } = item;
          if (skuId) {
            await transactionalEntityManager.createQueryBuilder(Sku, 'sku')
              .update()
              .set({
                specCombination,
                price,
                stock,
                good: await transactionalEntityManager.createQueryBuilder(Good, 'good').where('id = :id', { id }).getOne(),
              })
              .where('sku.id = :id', { id: skuId })
              .execute();

          } else {
            await transactionalEntityManager.createQueryBuilder(Sku, 'sku')
              .insert()
              .values({
                specCombination,
                stock,
                price,
                good: await transactionalEntityManager.createQueryBuilder(Good, 'good').where('id = :id', { id }).getOne(),
              })
              .execute();
          }

        }));
      });
    }

  }

  async remove(deleteIds: DeleteIds) {
    await this.entityManger.transaction(async transactionalEntityManager => {
      await Promise.all(deleteIds.ids.map(async (num) => {

        //删除 sku
        await transactionalEntityManager.createQueryBuilder(Sku, 'sku')
          .delete()
          .where('sku.goodId = :id', { id: num })
          .execute();

        //删除 spec
        await transactionalEntityManager.createQueryBuilder(Spec, 'spec')
          .delete()
          .where('spec.goodId = :id', { id: num })
          .execute();

        //删除 good
        await transactionalEntityManager.createQueryBuilder(Good, 'good')
          .delete()
          .where('good.id = :id', { id: num })
          .execute();
      }));
    });
    return '删除成功';
  }
}
